#include "KBD.h"
#include "../NoQuake/events.h"

#pragma data_seg (".shared")
static HHOOK hkb = NULL;
static HINSTANCE hins = NULL;
static HWND hwnd = NULL;
static bool globalKeys[256] = {false};
static int required[256] = {0};
static int nReq = 0;
#pragma data_seg ()

static const int NUM_GAMES				= 5;
static const TCHAR *GAMES_CLASSES[NUM_GAMES] = 
{
	TEXT("Quake4"),
	TEXT("ETQW"),
	TEXT("DOOM3"),
	TEXT("Quake 3: Arena"),
	TEXT("Enemy Territory")
};

int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
	if (NULL == hins) hins = hInstance;
	return TRUE;
}

extern "C" LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (HC_ACTION == nCode) {
		if (0 == (static_cast<DWORD>(lParam) & (1 << 31)) && 0 == (static_cast<DWORD>(lParam) & (1 << 30))) {
			// WM_KEYDOWN
			SendMessage(hwnd, NQ_KBD_EVENT, wParam, lParam);
			globalKeys[wParam] = true;
			bool toggle = true;
			for (int i = 0; toggle && i < nReq; ++i) toggle = toggle && globalKeys[required[i]];
			if (toggle) {
				HWND wndQuake = NULL;
				for (int i = 0; NULL == wndQuake && i < NUM_GAMES; ++i)
					wndQuake = FindWindow(GAMES_CLASSES[i], NULL);
				if (NULL != wndQuake) {									// if found window, toggle visibility
					WINDOWPLACEMENT wp;
					wp.length = sizeof(WINDOWPLACEMENT);
					GetWindowPlacement(wndQuake, &wp);
					if (wp.showCmd != SW_SHOWNORMAL) {
						//ShowWindow(wndQuake, SW_SHOW);
						ShowWindow(wndQuake, SW_RESTORE);
					}
					else {
						ShowWindow(wndQuake, SW_MINIMIZE);
						//ShowWindow(wndQuake, SW_HIDE);
					}
					for (int i = 0; i < nReq; ++i) globalKeys[required[i]] = false;
					return 1;
				}
			}
		}
		else if (static_cast<DWORD>(lParam) & (1 << 31)) {
			// WM_KEYUP
			SendMessage(hwnd, NQ_KBD_EVENT, wParam, lParam);
			globalKeys[wParam] = false;
		}
	}
	return CallNextHookEx(hkb, nCode, wParam, lParam);
}

extern "C" void SetHotKeys(int n, const int *kz)
{
	nReq = n;
	for (int i = 0; i < nReq; ++i)
		required[i] = kz[i];
}

extern "C" void InstallHook(HWND hWnd)
{
	hwnd = hWnd;
	hkb = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, hins, 0);
	if (NULL == hkb) {
		TCHAR msg[256];
		wsprintf(msg, TEXT("Cannot install keyboard hook, code: %d"), GetLastError());
		MessageBox(hwnd, msg, TEXT("error"), MB_ICONERROR);
	}
}

extern "C" void ReleaseHook()
{
	if (hkb != NULL) {
		BOOL bRes = UnhookWindowsHookEx(hkb);
		if (!bRes) MessageBox(hwnd, TEXT("Cannot remove keyboard hook."), TEXT("error"), MB_ICONERROR);
	}
}
